package incremental

import (
	"calculator/internal/core/dag"
	"calculator/internal/core/expr"

	"github.com/pkg/errors"

	"calculator/internal/core/schema"
	"fmt"

	"gorm.io/gorm"
)

// Computer 增量计算引擎
type Computer struct {
	dagBuilder  *dag.DAGBuilder // 依赖图构建器
	dagInstance *dag.DAG        // 依赖图
	exprEval    *expr.Evaluator // 表达式评估器
	schema      *schema.Schema  // 数据模型
	db          *gorm.DB        // 数据库连接
}

// NewComputer 创建增量计算引擎实例
func NewComputer(db *gorm.DB) *Computer {
	exprEval := expr.NewEvaluator(db)
	exprEval.RegisterFunctions()

	return &Computer{
		dagBuilder:  nil,
		dagInstance: nil,
		exprEval:    exprEval,
		schema:      nil,
		db:          db,
	}
}

func (c *Computer) UpdateSchema(schemaValue *schema.Schema) error {
	dagBuilder := dag.NewDAGBuilder(schemaValue, c.db)
	dagInstance, err := dagBuilder.Build()
	if err != nil {
		return err
	}
	c.dagBuilder = dagBuilder
	c.dagInstance = dagInstance
	c.schema = schemaValue
	return nil
}

// ProcessChanges 处理数据变更并执行增量计算
func (c *Computer) ProcessChanges(changes []*Change) ([]*Change, error) {
	if c.dagInstance == nil {
		return nil, errors.New("依赖图未初始化")
	}

	// 1. 识别受影响的节点
	affectedNodes := c.identifyAffectedNodes(changes, c.dagInstance)

	// 2. 执行拓扑排序
	sortedNodes, err := c.dagInstance.TopologicalSort()
	if err != nil {
		return nil, errors.Wrap(err, "INC002")
	}

	// 3. 筛选需要重新计算的节点
	computeNodes := c.filterComputeNodes(sortedNodes, affectedNodes)

	// 4. 执行计算并收集新的变更
	resultChanges, err := c.executeComputations(computeNodes, changes, c.dagInstance)
	if err != nil {
		return nil, err
	}

	return resultChanges, nil
}

// 识别受影响的节点
func (c *Computer) identifyAffectedNodes(changes []*Change, graph *dag.DAG) map[string]bool {
	affected := make(map[string]bool)

	for _, change := range changes {
		// 为变更的记录创建节点ID
		recordNodeID := fmt.Sprintf("record:%s:%s:%v", change.ModelName, change.TableName, change.RecordID)
		affected[recordNodeID] = true

		// 添加该记录的所有字段节点
		for fieldName := range change.NewValues {
			fieldNodeID := fmt.Sprintf("field:%s:%s:%v:%s", change.ModelName, change.TableName, change.RecordID, fieldName)
			affected[fieldNodeID] = true
		}

		// 对于更新操作，也要考虑旧值字段
		for fieldName := range change.OldValues {
			fieldNodeID := fmt.Sprintf("field:%s:%s:%v:%s", change.ModelName, change.TableName, change.RecordID, fieldName)
			affected[fieldNodeID] = true
		}
	}

	return affected
}

// 筛选需要重新计算的节点
func (c *Computer) filterComputeNodes(sortedNodes []*dag.Node, affectedNodes map[string]bool) []*dag.Node {
	var computeNodes []*dag.Node
	processed := make(map[string]bool)

	// 反向遍历拓扑排序结果，确保依赖先被处理
	for i := len(sortedNodes) - 1; i >= 0; i-- {
		node := sortedNodes[i]
		if affectedNodes[node.ID] && !processed[node.ID] {
			computeNodes = append(computeNodes, node)
			processed[node.ID] = true

			// 标记所有依赖此节点的节点也需要计算
			c.markDependents(node.ID, sortedNodes, processed, computeNodes)
		}
	}

	// 恢复为正向顺序
	for i, j := 0, len(computeNodes)-1; i < j; i, j = i+1, j-1 {
		computeNodes[i], computeNodes[j] = computeNodes[j], computeNodes[i]
	}

	return computeNodes
}

// 标记依赖节点
func (c *Computer) markDependents(nodeID string, sortedNodes []*dag.Node, processed map[string]bool, computeNodes []*dag.Node) {
	// TODO: 实现依赖节点标记逻辑
}

// 执行计算
func (c *Computer) executeComputations(nodes []*dag.Node, changes []*Change, graph *dag.DAG) ([]*Change, error) {
	// TODO: 实现计算执行逻辑
	return changes, nil
}
